﻿/* 
 * Rug.Cmd part of Rugland Console Framework
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * Copyright (C) 2008 Phill Tew. All rights reserved.
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Rug.Cmd.Colors;

namespace Rug.Cmd
{
	public static class CmdHelper
	{
		#region Banner Helper 
		
		public static void WriteSimpleBanner(string str, char fill, ConsoleColorExt ForeColour, ConsoleColorExt BackColour)
		{
			WriteSimpleBanner(str, fill, 0, ForeColour, BackColour);
		}

		public static void WriteSimpleBanner(string str, char fill, int paddingRight, ConsoleColorExt ForeColour, ConsoleColorExt BackColour)
		{
			ConsoleColorState state = RC.ColorState;

			int total = RC.BufferWidth - paddingRight;

			int dif = (total - str.Length) / 2;

			if (ForeColour != ConsoleColorExt.Inhreit)
				RC.ForegroundColor = ForeColour;
			if (BackColour != ConsoleColorExt.Inhreit)
				RC.BackgroundColor = BackColour;

			if (paddingRight > 0)
			{
				RC.Write(ConsoleVerbosity.Silent, new string(fill, dif) + str + new string(fill, total - (dif + str.Length)));
				RC.ColorState = state;
				RC.WriteLine(ConsoleVerbosity.Silent);
			}
			else
			{
				RC.Write(ConsoleVerbosity.Silent, new string(fill, dif) + str + new string(fill, total - (dif + str.Length)));
				RC.ColorState = state;
				RC.Write(ConsoleVerbosity.Silent, new string(' ', RC.BufferWidth));

				if (RC.CanManipulateBuffer)
					RC.CursorTop = RC.CursorTop - 1;
			}
		}

		#endregion

		#region Padding Strings

		/// <summary>
		/// Trim or pad a string to a max length
		/// </summary>
		/// <param name="str">the string to trim / pad</param>
		/// <param name="totalWidth">the total length of the string</param>
		/// <param name="paddingChar">the char to be used as a padding char</param>
		/// <param name="appendIfCut">the string to append if the string was cut</param>
		/// <returns>a trimmed or padded string</returns>
		public static string MaxLengthPadded(string str, int totalWidth, char paddingChar, string appendIfCut)
		{
			if (str.Length > totalWidth)
				return str.Substring(0, totalWidth - appendIfCut.Length) + appendIfCut;
			else
				return str.PadRight(totalWidth, paddingChar);
		}

		/// <summary>
		/// Trim or pad a string to a max length and making the string left alligned
		/// </summary>
		/// <param name="str">the string to trim / pad</param>
		/// <param name="totalWidth">the total length of the string</param>
		/// <param name="paddingChar">the char to be used as a padding char</param>
		/// <param name="appendIfCut">the string to append if the string was cut</param>
		/// <returns>a trimmed or padded string</returns>
		public static string MaxLengthLeftPadded(string str, int totalWidth, char paddingChar, string appendIfCut)
		{
			if (str.Length > totalWidth)
				return str.Substring(0, totalWidth - appendIfCut.Length) + appendIfCut;
			else
				return str.PadLeft(totalWidth, paddingChar);
		}

		#endregion

		#region Format memory bytes as string
		
		/// <summary>
		/// Format bytes as string e.g 256KB
		/// </summary>
		/// <param name="bytes">number of bytes</param>
		/// <param name="maxLength">max string length</param>
		/// <returns>bytes formatted as a string</returns>
		public static string GetMemStringFromBytes(long bytes, int maxLength)
		{
			return GetMemStringFromBytes(bytes, false).PadLeft(maxLength, ' ');
		}

		/// <summary>
		/// Format bytes as string e.g 256 KB
		/// </summary>
		/// <param name="bytes">number of bytes</param>
		/// <param name="maxLength">max string length</param>
		/// <param name="space">include a space char inbetween the number and the scale</param>
		/// <returns>bytes formatted as a string</returns>
		public static string GetMemStringFromBytes(long bytes, int maxLength, bool space)
		{
			return GetMemStringFromBytes(bytes, space).PadLeft(maxLength, ' ');
		}

		/// <summary>
		/// Format bytes as string e.g 256 KB
		/// </summary>
		/// <param name="bytes">number of bytes</param>
		/// <param name="space">include a space char inbetween the number and the scale</param>
		/// <returns>bytes formatted as a string</returns>
		public static string GetMemStringFromBytes(long bytes, bool space)
		{
			decimal kiloBytes = (decimal)bytes / 1024m;
			string scaleString = "KB";

			while (kiloBytes >= 1000)
			{
				if (scaleString == "KB")
				{
					kiloBytes /= 1024m;
					scaleString = "MB";
				}
				else if (scaleString == "MB")
				{
					kiloBytes /= 1024m;
					scaleString = "GB";
				}
				else if (scaleString == "GB")
				{
					kiloBytes /= 1024m;
					scaleString = "TB";
				}
				else if (scaleString == "TB")
				{
					kiloBytes /= 1024m;
					scaleString = "PB";
				}
				else if (scaleString == "PB")
				{
					kiloBytes /= 1024m;
					scaleString = "XB";
				}
				else if (scaleString == "XB")
				{
					kiloBytes /= 1024m;
					scaleString = "ZB";
				}
				else if (scaleString == "ZB")
				{
					kiloBytes /= 1024m;
					scaleString = "YB";
				}
				else if (scaleString == "YB")
				{
					kiloBytes /= 1024m;
					scaleString = "??";
				}
				else
				{
					kiloBytes /= 1024m;
				}
			}

			return kiloBytes.ToString("N2") + (space ? " " + scaleString : scaleString);
		}

		#endregion

		#region Simple Label : value formatting
		
		/// <summary>
		/// Write a simple Label : Value string to the console. The value is trimmed / padded to 22 chars 
		/// </summary>
		/// <param name="verbose">the verbosity level</param>
		/// <param name="label">label string</param>
		/// <param name="value">value string</param>
		/// <param name="valueColor">the color for the value</param>
		public static void WriteInfoToConsole(ConsoleVerbosity verbose, string label, string value, ConsoleColorExt valueColor)
		{
			if ((int)RC.Verbosity >= (int)verbose)
			{
				WriteInfoToConsole(label, value, valueColor, false);
			}
		}

		/// <summary>
		/// Write a simple Label : Value string to the console. The value is trimmed / padded to 22 chars 
		/// </summary>
		/// <param name="label">label string</param>
		/// <param name="value">value string</param>
		/// <param name="valueColor">the color for the value</param>
		public static void WriteInfoToConsole(string label, string value, ConsoleColorExt valueColor)
		{
			RC.Write(ConsoleThemeColor.TitleText, " " + label.PadRight(18) + ":");
			RC.Write(ConsoleThemeColor.SubText, new string('.', 22 - value.Length));
			RC.WriteLine(valueColor, value);
		}

		/// <summary>
		/// Write a simple Label : Value string to the console
		/// </summary>
		/// <param name="verbose">the verbosity level</param>
		/// <param name="label">label string</param>
		/// <param name="value">value string</param>
		/// <param name="valueColor">the color for the value</param>
		/// <param name="extended">true if the value should not be padded</param>
		public static void WriteInfoToConsole(ConsoleVerbosity verbose, string label, string value, ConsoleColorExt valueColor, bool extended)
		{
			if ((int)RC.Verbosity >= (int)verbose)
			{
				WriteInfoToConsole(label, value, valueColor, extended);
			}
		}

		/// <summary>
		/// Write a simple Label : Value string to the console
		/// </summary>
		/// <param name="label">label string</param>
		/// <param name="value">value string</param>
		/// <param name="valueColor">the color for the value</param>
		/// <param name="extended">true if the value should not be padded</param>
		public static void WriteInfoToConsole(string label, string value, ConsoleColorExt valueColor, bool extended)
		{
			RC.Write(ConsoleThemeColor.TitleText, " " + label.PadRight(18) + ":");

			if (extended)
			{
				RC.WriteLine(valueColor, value);
			}
			else
			{
				if (value.Length < 22)
				{
					RC.Write(ConsoleThemeColor.SubText, new string('.', 22 - value.Length));
					RC.WriteLine(valueColor, value);
				}
				else
				{
					RC.WriteLine(valueColor, value.Substring(value.Length - 22));
				}
			}
		}

		#endregion

		#region Write a logo to the console
		
		/// <summary>
		/// Writes a simple scaleable ASCII logo to the console
		/// </summary>
		/// <param name="x">x position</param>
		/// <param name="y">y position</param>
		/// <param name="pixWidth">width of each 'pixel'</param>
		/// <param name="pixHeight">height of each 'pixel'</param>
		/// <param name="fillShade">the shade char to fill with</param>
		/// <param name="endShade">the shade char to end with</param>
		/// <param name="shadowShade">the shade char to fill shadow with</param>
		/// <param name="makeSpace">write a blank space before writing the logo</param>
		/// <param name="replaceCursor">replace the cursor to where it was when the write began</param>
		/// <param name="lines">the logo lines</param>
		public static void WriteLogo(int x, int y, int pixWidth, int pixHeight, ConsoleShade fillShade, ConsoleShade endShade, ConsoleShade shadowShade, bool makeSpace, bool replaceCursor, string[] lines)
		{
			if (!RC.CanManipulateBuffer)
				return;

			int cursorLeft = RC.CursorLeft;
			int cursorTop = RC.CursorTop;

			if (makeSpace)
			{
				RC.CursorLeft = x;
				RC.CursorTop = y;

				for (int i = 0, ie = pixHeight * lines.Length; i < ie; i++)
					RC.WriteLine();

				if (!replaceCursor)
				{
					cursorLeft = RC.CursorLeft;
					cursorTop = RC.CursorTop;
				}
			}

			WriteLogo(x, y, pixWidth, pixHeight, fillShade, endShade, shadowShade, lines);

			RC.CursorTop = cursorTop;
			RC.CursorLeft = cursorLeft;
		}

		/// <summary>
		/// Writes a simple scaleable ASCII logo to the console
		/// </summary>
		/// <param name="x">x position</param>
		/// <param name="y">y position</param>
		/// <param name="pixWidth">width of each 'pixel'</param>
		/// <param name="pixHeight">height of each 'pixel'</param>
		/// <param name="fillShade">the shade char to fill with</param>
		/// <param name="endShade">the shade char to end with</param>
		/// <param name="shadowShade">the shade char to fill shadow with</param>
		/// <param name="lines">the logo lines</param>
		public static void WriteLogo(int x, int y, int pixWidth, int pixHeight, ConsoleShade fillShade, ConsoleShade endShade, ConsoleShade shadowShade, string[] lines)
		{
			if (!RC.CanManipulateBuffer)
				return;

			ConsoleColorState state = RC.ColorState;

			int cursorLeft = RC.CursorLeft;
			int cursorTop = RC.CursorTop;

			string block = new string(ConsoleChars.GetShade(fillShade), pixWidth);

			string end = "";

			if (pixWidth > 1)
			{
				end = new string(ConsoleChars.GetShade(fillShade), pixWidth - 1) + ConsoleChars.GetShade(endShade);
			}
			else
			{ 
				end = new string(ConsoleChars.GetShade(endShade), 1);
			}

			string blank = new string(ConsoleChars.GetShade(ConsoleShade.Clear), pixWidth);

			string shadow = new string(ConsoleChars.GetShade(shadowShade), pixWidth);
			string halfShadow = "";

			if (pixWidth > 1)
			{
				halfShadow = new string(ConsoleChars.GetShade(shadowShade), 1) + new string(ConsoleChars.GetShade(ConsoleShade.Clear), pixWidth - 1);
			}
			else
			{
				halfShadow = new string(ConsoleChars.GetShade(shadowShade), 1);
			}

			int ypos = y;

			RC.CursorLeft = x;
			RC.CursorTop = ypos++;

			RC.ForegroundThemeColor = ConsoleThemeColor.TitleText;

			for (int j = 0; j < lines.Length; j++)
			{ 
				for (int i = 0; i < pixHeight; i++)
				{
					RC.Write(string.Format(lines[j], block, end, blank, shadow, halfShadow));

					RC.CursorLeft = x;
					RC.CursorTop = ypos++;
				}
			}

			RC.ColorState = state;

			RC.CursorTop = cursorTop;
			RC.CursorLeft = cursorLeft;
		}

		#region Rugland Spacific Logo
		
		// ..|. |..
		// .  . |. .
		// .  ..|...
		private static string[] RuglandLogo = new string[] { 
			"{0}{0}{1}{0}{2}{1}{0}{0}{2}", 
			"{0}{2}{2}{0}{2}{1}{0}{2}{0}", 
			"{0}{2}{2}{0}{0}{1}{0}{0}{0}" }; 

		public static void WriteRuglandLogo(int x, int y, int pixWidth, int pixHeight, bool divideChars, ConsoleShade fillShade, bool makeSpace, bool replaceCursor)
		{
			WriteLogo(x, y, pixWidth, pixHeight, fillShade, divideChars ? ConsoleShade.HalfLeft : ConsoleShade.Opaque, ConsoleShade.Dark, makeSpace, replaceCursor, RuglandLogo);
		}       

		public static void WriteRuglandLogo(int x, int y, int pixWidth, int pixHeight, bool divideChars, ConsoleShade fillShade)
		{
			WriteLogo(x, y, pixWidth, pixHeight, fillShade, divideChars ? ConsoleShade.HalfLeft : ConsoleShade.Opaque, ConsoleShade.Dark, RuglandLogo);
		}

		#endregion

		#endregion
	}
}
